#include "Server.h"
#include "ClientHandler.h"

#include <QSqlQuery>
#include <QSqlError>

Server::Server(QObject *parent)
    : QObject{parent}
{
    // 实例化WebSocket对象
    m_webSocket = new QWebSocketServer("MySmallTalkServer",QWebSocketServer::NonSecureMode,this);
    // 实例化连接池对象
    m_connectionPool = new ConnectionPool();
    // 保存全局线程池对象，并设置最大线程数
    m_threadPool = QThreadPool::globalInstance();
    m_threadPool->setMaxThreadCount(300);// 限制最多为300个线程

    // 获取并保存自身的数据库连接
    m_db = getDBConnection();

    // 开启监听
    webSocketListen();
}

Server::~Server()
{
    // 析构时释放自身的数据库连接
    releaseDBConnection(m_db);

    // 释放堆上的内存
    if(m_connectionPool){
        delete m_connectionPool;
    }
    if(m_webSocket){
        delete m_webSocket;
    }
}

void Server::webSocketListen()
{
    // 尝试开启监听，端口8899
    if(m_webSocket->listen(QHostAddress::Any, 8899)){
        connect(m_webSocket,&QWebSocketServer::newConnection,this,&Server::onNewConnection);
        qDebug()<<"服务器开启监听，端口8899";
    }else{
        qDebug()<<"服务器无法开启监听！";
    }
}


void Server::onNewConnection()
{
    // 获取到新连接的套接字
    QWebSocket* socket = m_webSocket->nextPendingConnection();
    if(!socket){
        qDebug()<<"服务器新连接套接字获取为空";
        return;
    }

    if(socket->isValid()){
        qDebug()<<"服务器收到新的连接";

        // 实例化新客户的连接
        ClientHandler* handler = new ClientHandler(socket,"-1",this);

        // 确保在断开时候自动释放
        connect(socket,&QWebSocket::disconnected,handler,&ClientHandler::deleteLater);

        // 存储到哈希表的逻辑由handler确定了自己的账号后再添加

    }else{
        qDebug()<<"服务器获取到的套接字无效";
        socket->deleteLater();
    }
}

void Server::addClientToHash(const QString &account, ClientHandler *handler)
{
    // 由于多个用户指针共用Server，所以需要写锁来保护对哈希表的修改操作
    QWriteLocker locker(&m_lock);
    if(!m_clientMap.contains(account)){
        m_clientMap.insert(account, handler);
    }
}

void Server::removeClientToHash(const QString &account)
{
    // 由于多个用户指针共用Server，所以需要写锁来保护对哈希表的修改操作
    QWriteLocker locker(&m_lock);
    if(m_clientMap.contains(account)){
        ClientHandler* c = m_clientMap[account];
        if(c){
            c->deleteLater();// 释放这个内存
        }
        m_clientMap.remove(account);
    }
}

QSqlDatabase Server::getDBConnection()
{
    return m_connectionPool->getConnection();
}

void Server::releaseDBConnection(QSqlDatabase &db)
{
    m_connectionPool->releaseConnection(db);
}

ClientHandler *Server::getClientHandlerByAccount(QString account)
{
    // 由于多个用户指针共用Server，所以需要读锁来保护对哈希表的修改操作
    QReadLocker locker(&m_lock);
    if(m_clientMap.contains(account)){
        return m_clientMap[account];
    }
    return nullptr;
}

